Term Structures
Customization
Term structure charts can be customized to present different kinds of information or to enhance understanding of the term structure data.
In this tutorial
You will customize the data, formatting, and layout of a basic term structure chart.
Before you begin
This tutorial requires version 8.3.0 or later of the ChartIQ library including the Cross Section plug-in.
The tutorial is a continuation of the Term Structures Introduction tutorial.
Please complete the introduction before proceeding.
Customize the chart
We'll customize the termstructure.html file we created in the introductory tutorial.
Here's where we left off:
<!doctype html>
<html>
<head>
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<!-- Include the main ChartIQ CSS file. -->
<link rel="stylesheet" type="text/css" href="css/stx-chart.css" media="screen" />
</head>
<body>
<!-- Create the container for the chart. -->
<div class="chartContainer" style="width: 1200px; height: 675px; position: relative;"></div>
<!-- This inline script acts as the entry point, without creating a separate external file. -->
<script type="module">
// Reference the main ChartIQ library.
import { CIQ } from "./js/standard.js";
// Reference the Cross Section plug-in.
import "./plugins/crosssection/core.js";
// Create a chart engine instance.
var stxx = new CIQ.ChartEngine({container: document.querySelector(".chartContainer")});
// Create a cross section object and associate it with the chart engine.
new CIQ.CrossSection({stx: stxx, useQuotefeed: false});
// Notify the chart engine of the chart type.
stxx.setChartType("crosssection");
// Load the chart.
stxx.loadChart("US-T BENCHMARK", {
masterData: quotes // Add a data source to the chart.
});
</script>
</body>
<!-- Create a static data source for the term structure. -->
<script>
var quotes = [
{
DT: new Date(),
Date: new Date().toISOString(),
termStructure: {
"1 MO": {yield: 2.31},
"2 MO": {yield: 2.37},
"3 MO": {yield: 2.41},
"6 MO": {yield: 2.53},
"1 YR": {yield: 2.70},
"2 YR": {yield: 2.83},
"3 YR": {yield: 2.86},
"5 YR": {yield: 2.89},
"7 YR": {yield: 2.98},
"10 YR": {yield: 3.06},
"20 YR": {yield: 3.22},
"30 YR": {yield: 3.32}
}
}
];
</script>
</html>
Data source
Let's begin by adding some data to our term structure instruments. Replace the termStructure
property in the static data source in termstructure.html with the following:
termStructure: {
"1 MO": { yield: 2.31, bid: 77.27, mid: 79.27, ask: 81.27 },
"2 MO": { yield: 2.37, bid: 80.89, mid: 82.89, ask: 84.89 },
"3 MO": { yield: 2.41, bid: 83.06, mid: 85.06, ask: 87.06 },
"6 MO": { yield: 2.53, bid: 85.64, mid: 87.64, ask: 89.64 },
"1 YR": { yield: 2.70, bid: 89.57, mid: 91.57, ask: 93.57 },
"2 YR": { yield: 2.83, bid: 92.82, mid: 94.82, ask: 96.82 },
"3 YR": { yield: 2.86, bid: 93.11, mid: 95.11, ask: 97.11 },
"5 YR": { yield: 2.89, bid: 96.06, mid: 98.06, ask: 100.06 },
"7 YR": { yield: 2.98, bid: 96.48, mid: 98.48, ask: 100.48 },
"10 YR": { yield: 3.06, bid: 99.94, mid: 101.94, ask: 103.94 },
"20 YR": { yield: 3.22, bid: 103.52, mid: 105.52, ask: 107.52 },
"30 YR": { yield: 3.32, bid: 105.52, mid: 107.52, ask: 109.52 }
}
Treasury instruments are bought and sold through financial markets (they can also be bought directly from the U.S. Treasury). The bid
, mid
, and ask
values are the dollar amounts at which the instruments are trading at a given point in time. The point in time is specified by the DT
and Date
properties of the quote object.
The bid is the price buyers are willing to pay for the instrument. The ask is the price sellers are willing to accept for the instrument. The mid is the average of the bid and ask.
Y-axis values
The term structure chart, by default, plots yield
as the instrument value; that is, the y-axis values.
To plot a different field, include the optional dataField
parameter in the call to the CIQ.CrossSection constructor function and set its value to the key of one of the data fields; for example, dataField: "bid"
.
Revise the CIQ.CrossSection
constructor call in termstructure.html as follows:
new CIQ.CrossSection({stx: stxx, useQuotefeed: false, dataField: "bid"});
Load the file into your web browser to see how the chart has changed.
Try setting the data field to "ask" and "mid".
Y-axis formatting
Some data fields are best displayed as raw values, some as percentages. ChartIQ enables you to format term structure y-axis values either way.
You may have noticed that yield
is formatted as a percentage but bid
, ask
, and mid
are not. Yields are typically expressed as percentages, so CIQ.CrossSection
formats them that way by default.
To format other values as percentages, include the optional fieldsToFormatAsPercent
parameter in the CIQ.CrossSection constructor function call. Set an array as the value of the parameter, then add the name of the data field to the array, for example: fieldsToFormatAsPercent: ["bid"]
. The default value is ["yield"]
.
Revise the CIQ.CrossSection
constructor function call as follows:
new CIQ.CrossSection({stx: stxx, useQuotefeed: false, dataField: "bid", fieldsToFormatAsPercent: ["bid"]});
You can add "ask" and "mid" to the fieldsToFormatAsPercent
array to display their values as percentages.
Load the file to see the change to the y-axis legend.
Note: The values of bid
, ask
, and mid
are dollar amounts, so formatting them as percentages doesn't make sense, but the fieldsToFormatAsPercent
parameter enables you to format any field as a percentage.
Shading
The background shading of term structure charts helps you visually group instruments that are similar.
The shading can be customized by specifying RBGA color values in CSS styles defined for the term structure instruments. The term structure plug‑in looks for CSS class names that take the form: .stx_shading_ + <instrument name with spaces removed>
; for example, .stx_shading_1MO
(see Data source above for the instrument names).
Add the following style
element to termstructure.html:
<style>
.stx_shading_1MO,
.stx_shading_2MO,
.stx_shading_3MO,
.stx_shading_6MO {
background-color: rgba(162, 199, 255, 0.3);
}
.stx_shading_1YR,
.stx_shading_2YR,
.stx_shading_3YR,
.stx_shading_5YR,
.stx_shading_7YR {
background-color: rgba(95, 159, 255, 0.3);
}
.stx_shading_10YR,
.stx_shading_20YR,
.stx_shading_30YR {
background-color: rgba(20, 97, 212, 0.3);
}
</style>
You can insert the style
element wherever you like in the file; stx-chart.css does not contain these styles.
Feel free to extract the styles into an external CSS style sheet.
Reload termstructure.html file to see the background shading.
Scaling
Term structure charts feature the concept of scaled spacing. Instruments can be non-uniformly spaced based on delivery dates or contract expiration dates or some other criterion that implies non-uniform differences among the instruments. The Treasury yield curve is a good example: maturity dates occur in the irregular time sequence of 1 Mo, 2 Mo, 3 Mo, 6 Mo, 1 Yr, 2 Yr, 3 Yr, 5 Yr, 7 Yr, 10 Yr, 20 Yr, and 30 Yr.
A uniform representation of those time-to-maturity differences in actual time values (such as months) would produce a chart with most of the data points tightly clustered on the left side of the chart. To spread out the data while still providing a sense of the relative differences among instruments, the data points are plotted along the x-axis using a scaling algorithm that is effectively logarithmic.
You can create a custom spacing algorithm by overriding the default calculateScaledSpacingUnits method of CIQ.CrossSection
. The only thing the term structure plug-in expects is that the returned spacingUnits
object contains key/value pairs for all instruments, where the keys identify the instruments, and the values represent the number of spacing units for the instrument. Number of spacing units is a weighting that determines the instrument's share of the horizontal space. The renderer adds up all the spacing units and allocates a percentage of horizontal space to each instrument based on how many spacing units the instrument has relative to the total amount.
Add the following custom calculateScaledSpacingUnits
function to the entry point script in termstructure.html:
CIQ.CrossSection.prototype.calculateScaledSpacingUnits = function(instruments) {
let spacingUnits = {};
function calculateValue(instrument) {
let [value, type] = instrument.split(" ");
value = parseInt(value);
if (type === "WK") value *= 7;
if (type === "MO") value *= 30;
if (type === "YR") value *= 30 * 12;
return value;
}
for (let i = 0; i < instruments.length; i++) {
let instrument = instruments[i];
let previousInstrument = instruments[i - 1];
// No spacing for first entry.
if (i === 0) {
spacingUnits[instrument] = 0;
continue;
}
let value = calculateValue(instrument) - calculateValue(previousInstrument);
value = Math.pow(value, 0.5);
spacingUnits[instrument] = value;
}
return spacingUnits;
};
Note: For the override to work, you have to add the function after the statement that imports the term structure plug-in:
import "plugins/crosssection/core.js";
Tip: To change the instrument spacing, adjust the power in the following statement:
value = Math.pow(value, 0.5);
Set the power to zero to space the instruments evenly; 1, to space them based on the number of months. Vary the power and see what you get.
The customized chart
Here's an example of what termstructure.html might look like with all of our customizations in place:
<!doctype html>
<html>
<head>
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<!-- Include the main ChartIQ CSS file. -->
<link rel="stylesheet" type="text/css" href="css/stx-chart.css" media="screen" />
<!-- Create the background shading styles. -->
<style>
.stx_shading_1MO,
.stx_shading_2MO,
.stx_shading_3MO,
.stx_shading_6MO {
background-color: rgba(162, 199, 255, 0.3);
}
.stx_shading_1YR,
.stx_shading_2YR,
.stx_shading_3YR,
.stx_shading_5YR,
.stx_shading_7YR {
background-color: rgba(95, 159, 255, 0.3);
}
.stx_shading_10YR,
.stx_shading_20YR,
.stx_shading_30YR {
background-color: rgba(20, 97, 212, 0.3);
}
</style>
</head>
<body>
<!-- Create the container for the chart. -->
<div class="chartContainer" style="width: 1200px; height: 675px; position: relative;"></div>
<!-- This inline script acts as the entry point, without creating a separate external file. -->
<script type="module">
// Reference the main ChartIQ library.
import { CIQ } from "./js/standard.js";
// Reference the Cross Section plug-in.
import "./plugins/crosssection/core.js";
// Create a chart engine instance.
var stxx = new CIQ.ChartEngine({container: document.querySelector(".chartContainer")});
// Create a cross section object and associate it with the chart engine.
new CIQ.CrossSection({stx: stxx, useQuotefeed: false, dataField: "bid", fieldsToFormatAsPercent: ["bid"]});
// Notify the chart engine of the chart type.
stxx.setChartType("crosssection");
// Load the chart.
stxx.loadChart("US-T BENCHMARK", {
masterData: quotes // Add a data source to the chart.
});
// Override the cross section function that scales the data points on the x-axis.
CIQ.CrossSection.prototype.calculateScaledSpacingUnits = function(instruments) {
let spacingUnits = {};
function calculateValue(instrument) {
let [value, type] = instrument.split(" ");
value = parseInt(value);
if (type === "WK") value *= 7;
if (type === "MO") value *= 30;
if (type === "YR") value *= 30 * 12;
return value;
}
for (let i = 0; i < instruments.length; i++) {
let instrument = instruments[i];
let previousInstrument = instruments[i - 1];
// No spacing for first entry.
if (i === 0) {
spacingUnits[instrument] = 0;
continue;
}
let value = calculateValue(instrument) - calculateValue(previousInstrument);
value = Math.pow(value, 0.5);
spacingUnits[instrument] = value;
}
return spacingUnits;
};
</script>
</body>
<!-- Create a static data source for the term structure. -->
<script>
var quotes = [
{
DT: new Date(),
Date: new Date().toISOString(),
termStructure: {
"1 MO": { yield: 2.31, bid: 77.27, mid: 79.27, ask: 81.27 },
"2 MO": { yield: 2.37, bid: 80.89, mid: 82.89, ask: 84.89 },
"3 MO": { yield: 2.41, bid: 83.06, mid: 85.06, ask: 87.06 },
"6 MO": { yield: 2.53, bid: 85.64, mid: 87.64, ask: 89.64 },
"1 YR": { yield: 2.70, bid: 89.57, mid: 91.57, ask: 93.57 },
"2 YR": { yield: 2.83, bid: 92.82, mid: 94.82, ask: 96.82 },
"3 YR": { yield: 2.86, bid: 93.11, mid: 95.11, ask: 97.11 },
"5 YR": { yield: 2.89, bid: 96.06, mid: 98.06, ask: 100.06 },
"7 YR": { yield: 2.98, bid: 96.48, mid: 98.48, ask: 100.48 },
"10 YR": { yield: 3.06, bid: 99.94, mid: 101.94, ask: 103.94 },
"20 YR": { yield: 3.22, bid: 103.52, mid: 105.52, ask: 107.52 },
"30 YR": { yield: 3.32, bid: 105.52, mid: 107.52, ask: 109.52 }
}
}
];
</script>
</html>
Load the file to see our improvements. The chart should look like this:

Conclusion
ChartIQ term structure charts are very customizable. The configuration parameters of CIQ.CrossSection make it easy.
Contact us at support@chartiq.com if you have any questions about term structure charts or the Cross Section plug-in.
Next steps
- Explore the CIQ.CrossSection API documentation.